//Purpose: socket operation wrapper and net buffer
//
//Created: Daly 2012-04-01

#include "ax_common.h"

//AxNetBuffer===================================================

AxNetBuffer::AxNetBuffer()
{
	buf = NULL;
	_len = 0;
	_alloc_size = 0;
	_start = 0;
	_end = 0;
}

AxNetBuffer::AxNetBuffer(unsigned int n)
{
	alloc(n);
}

AxNetBuffer::~AxNetBuffer()
{
	free(buf);
	buf = NULL;
}

void AxNetBuffer::alloc(unsigned int n)
{
	buf = (char*)malloc(n);
	_len = _end = 0;
	_alloc_size = n;
	_start = 0;
}

//shift to head
void AxNetBuffer::shift()
{
	memmove(buf, buf + _start, _len);
	_start = 0;
	_end = _len;
}

//pop the data ahead
//you should parse the data first
int AxNetBuffer::pop(unsigned int n)
{
	unsigned int len = _len;
	if (n >= _len) {
		_start = 0;
		_end = 0;
		_len = 0;
		return len;
	}
	_start += n;
	_len -= n;
	return _len;
}

//return: current data length 
int AxNetBuffer::push(const char* src, unsigned int size)
{
	unsigned int need;
	char* newp;
	need = _len + size;
	
	if (_end + size > _alloc_size) shift();
	
	if (need > _alloc_size) {
		//realloc
		_alloc_size = _start + need;
		buf = (char*)realloc(buf, _alloc_size);
		AX_ASSERT(buf != NULL);
	}
	memcpy(buf + _end , src, size);
	_len += size;
	_end += size;
	return _len;
}

//realloc size and clear data
void AxNetBuffer::reset(unsigned int size)
{
	_start = _end = 0;
	_len = 0;
	if (size > 0) {
		_alloc_size = size; 
		buf = (char*)realloc(buf, _alloc_size);
	} else {
		_alloc_size = 0;
		free(buf);
		buf = NULL;
	}
}

//===============================================================

//unit test
IMPLEMENT_UTEST(ax_net)
{
	char srcbuf[] = "abcdefghijklmnopqrstuvwxyz";
	char* p;
	AxNetBuffer buf1(100);
	AxNetBuffer buf2;	

	buf1.push(srcbuf, 10);
	p = buf1.datap();
	UTEST_ASSERT(p[1] == 'b');
	
	buf1.pop(3);
	p = buf1.datap();
	UTEST_ASSERT(p[0] == 'd');
	buf1.pop(100);
	//self expand
	buf2.push(srcbuf, 10);
	p = buf2.datap();
	UTEST_ASSERT(p[2] == 'c');

	ax_utest_log("ax_net utest ok");
}

